#include <map>
#include <string>
#include "debug.h"

using namespace std;

enum STATE
{
	SLEEPING,
	OCCURRING,
	PAUSED,
	STATE_LENGTH
};
enum EVENT_TYPE
{
	PRESENTATION,
	SELECTION,
	ATRIBUTION,
	COMPOSITION,
	POINTOVER, 	
	DRAG, 		
	FOCUS, 		
	EVENT_TYPE_LENGTH
};
enum EVENT
{
	START,
	STOP,
	PAUSE,
	RESUME,
	ABORT,
	EVENT_LENGTH
};
enum TRANSITION
{
	STARTS,
	STOPS,
	PAUSES,
	RESUMES,
	ABORTS,
	TRANSITION_LENGTH
};


class StateMachine
{
    	debug dbg;
	int repetitions;
	int occurrences;
	// currente state
	STATE state;
	map< STATE, string > 		str_state;
	map< EVENT, string > 		str_event;
	map< TRANSITION, string > 	str_transition;


	map< EVENT, STATE > 		state_evt;
	map< EVENT, TRANSITION > 	transition_evt;
public:
	StateMachine():state(SLEEPING)
	{
		dbg.log(__PRETTY_FUNCTION__, "new");
		buildTransitionTables();
		onEntryState();
	}
	
	void buildTransitionTables()
	{
		state_evt[START]=OCCURRING;
		state_evt[STOP]=SLEEPING;
		state_evt[PAUSE]=PAUSED;
		state_evt[RESUME]=OCCURRING;
		state_evt[ABORT]=SLEEPING;

		transition_evt[START]=STARTS;
		transition_evt[STOP]=STOPS;
		transition_evt[PAUSE]=PAUSES;
		transition_evt[RESUME]=RESUMES;
		transition_evt[ABORT]=ABORTS;

		str_state[SLEEPING]="SLEEPING";
		str_state[OCCURRING]="OCCURING";
		str_state[PAUSED]="PAUSED";

		str_event[START]="START";
		str_event[STOP]="STOP";
		str_event[PAUSE]="PAUSE";
		str_event[RESUME]="RESUME";
		str_event[ABORT]="ABORT";

		str_transition[STARTS]="STARTS";
		str_transition[STOPS]="STOPS";
		str_transition[PAUSES]="PAUSES";
		str_transition[RESUMES]="RESUMES";
		str_transition[ABORTS]="ABORTS";
	}

	void setState(STATE s)
	{
		state=s;
		dbg.log(__PRETTY_FUNCTION__, str_state[state]);
	}

	void onEntryState()
	{
		dbg.log(__PRETTY_FUNCTION__, str_state[state]);
	}

	void onExitState()
	{
		dbg.log(__PRETTY_FUNCTION__, str_state[state]);
	}

	void process_event(EVENT e)
	{

		if(!checkStateTransition(state_evt[e],e))
		{
			dbg.log(__PRETTY_FUNCTION__, "event:" + str_event[e] + " from state:" + str_state[state] + " Forbidden!");
			return;
		}

		dbg.log(__PRETTY_FUNCTION__, str_event[e]);
		onExitState();
		transition(transition_evt[e]);
		setState(state_evt[e]);
		onEntryState();
	}

	void transition(TRANSITION t)
	{
		dbg.log(__PRETTY_FUNCTION__, str_transition[t]);
	}

	
	bool checkStateTransition(STATE s, EVENT e)
	{
		switch (s)
		{
			case SLEEPING:
				if(state==OCCURRING || state==PAUSED)
				{
					return true;
				} 
			break;
			case OCCURRING:
				if(e==RESUME) 
				{
					if(state==PAUSED)
					{
						return true;
					}
					else
					{
						return false;
					}
				} 
				else 
				{
					if(state==SLEEPING)
					{
						return true;
					}
					else
					{
						return false;
					}
				} 
			break;
			case PAUSED:
				if(state==OCCURRING)
				{
					return true;
				} 
			break;
			default:
				return false;
		}
	}

	
	
};

int main()
{
	StateMachine sm;
	sm.process_event(ABORT);
	sm.process_event(RESUME);
	sm.process_event(PAUSE);
	sm.process_event(START);
	sm.process_event(PAUSE);
	sm.process_event(RESUME);
	sm.process_event(STOP);
	sm.process_event(STOP);
	sm.process_event(START);
	sm.process_event(ABORT);

	return 0;
}
